#!/usr/bin/env bash

rubygems_remove()
{
  \typeset rubygems_path __ruby entry

  rvm_log "Removing old Rubygems files..."

  case "$rvm_ruby_string" in
    (rbx-*)
      __ruby="['prefix']"
      ;;
    (*)
      __ruby=".values_at('sitelibdir','vendorlibdir').detect{ |path| File.directory?(File.join(path.to_s, 'rubygems')) }.to_s"
      ;;
  esac
  rubygems_path="$(${1:-ruby} -rrbconfig -e "puts ::Kernel.const_get('RbConfig')::CONFIG${ruby__}")"

  # Remove common files installed by ruby gems.
  entries=(
  "${rubygems_path}/ubygems.rb"
  "${rubygems_path}/gauntlet_rubygems.rb"
  "${rubygems_path}/rbconfig/"
  )
  for entry in "${entries[@]}" "${rubygems_path}/rubygems"*
  do
    __rvm_rm_rf "$entry"
  done
}

can_switch_rubygems()
{
  case "$rvm_ruby_string" in
    maglev*)
      return 1
      ;;
    *)
      return 0
      ;;
  esac
}

make_sure_jruby_can_work_with_rubygems()
{
  case "$rvm_ruby_string" in
    jruby-head*)
      true
      ;;
    jruby*)
      __rvm_version_compare "$rvm_ruby_version" -ge 1.7.1 || return 1
      ;;
    *)
      return 0 # do not care about other rubies
      ;;
  esac

  case "${rvm_rubygems_version}" in
    head|master)
      true
      ;;
    *)
      __rvm_version_compare "$rvm_rubygems_version" -ge 2.0.0 || return 1
      ;;
  esac
}

rubygems_fatal_error()
{
  rvm_error "$1"
  exit ${2:-1}
}

rubygems_version_list()
{
  __rvm_curl -sS https://rubygems.org/api/v1/versions/rubygems-update.json |
    __rvm_awk -v RS=',' -v FS='"' '$2=="number"{print $4}' |
    __rvm_version_sort |
    __rvm_grep '^[[:digit:]\.]*$'
}

rubygems_current_rubygems_version()
{
  "${rvm_ruby_binary}" -rrubygems -e 'puts(Gem::VERSION)' 2>/dev/null
}

rubygems_master_sha()
{
  __rvm_curl -s "https://api.github.com/repos/rubygems/rubygems/commits?page=last&per_page=1" |
    __rvm_sed -n '/^    "sha":/ {s/^.*".*": "\(.*\)".*$/\1/;p;}'
}

bundler_rubygems_master_sha()
{
  __rvm_curl -s "https://api.github.com/repos/rubygems/rubygems/contents/bundler" |
    __rvm_sed -n '/^  "sha":/ {s/^.*".*": "\(.*\)".*$/\1/;p;}'
}

rubygems_select_current()
{
  case "$version" in
    latest|current)
      version="$(__rvm_db "${rvm_ruby_string//-/_}_rubygems_version")"
      version="${version:-"$(__rvm_db "${rvm_ruby_interpreter}_${rvm_ruby_version}_rubygems_version")"}"
      if (( ${rvm_head_flag:-0} == 1 )) && [[ -z "${version:-}" ]]
      then version="$(__rvm_db "${rvm_ruby_interpreter}_head_rubygems_version")"
      fi
      version="${version:-"$(__rvm_db "${rvm_ruby_interpreter}_rubygems_version")"}"
      version="${version:-"$(__rvm_db "rubygems_version")"}"
      ;;
  esac
}

rubygems_select_latest()
{
  case "$version" in
    latest-*)
      version="${version#latest-}"
      version="$(rubygems_version_list | __rvm_grep "^${version}\." | __rvm_tail -n 1 )"
      version="${version}"
      ;;
  esac
}

rubygems_select_version_url()
{
  case "${version:-missing}" in
    ignore|none)
      rvm_rubygems_version="$version"
      ;;
    head|master)
      \typeset sha
      sha="$(rubygems_master_sha)"
      rvm_rubygems_version="$version"
      rvm_gem_package_name="rubygems-${sha}"
      rvm_gem_url="https://github.com/rubygems/rubygems/archive/${sha}.tar.gz"

      __bundler_sha="$(bundler_rubygems_master_sha)"
      __bundler_package_name="bundler-${__bundler_sha}"
      __bundler_url="https://github.com/bundler/bundler/archive/${__bundler_sha}.tar.gz"
      export rvm_verify_downloads_flag=1
      ;;
    v*)
      rvm_rubygems_version="$version"
      rvm_gem_package_name="rubygems-${version#v}"
      rvm_gem_url="https://github.com/rubygems/rubygems/archive/$version.tar.gz"
      export rvm_verify_downloads_flag=1
      ;;
    missing)
      rvm_error "There was an error while trying to resolve rubygems version for '$1'. \nHalting the installation."
      return 4
      ;;
    *)
      rvm_rubygems_version="$version"
      rvm_gem_package_name="rubygems-${rvm_rubygems_version}"
      rvm_rubygems_url=$(__rvm_db "rubygems_url")
      rvm_gem_url="${rvm_rubygems_url}/${rvm_gem_package_name}.tgz"
      ;;
  esac
}

rubygems_select_version()
{
  rubygems_select_current     "$1" &&
  rubygems_select_latest      "$1" &&
  rubygems_select_version_url "$1" ||
  return $?
}

__rvm_warn_on_rubyopt()
{
  if [[ -n "${RUBYOPT:-""}" ]]; then
    rvm_warn \
      "Please note: You have the RUBYOPT environment variable set and this \
            may interfere with normal rvm operations. We sugges unsetting it."
    return 1
  else
    return 0
  fi
}

rubygems_setup()
{
  export version="$1"
  \typeset __bundler_sha __bundler_package_name __bundler_url

  rvm_debug "rubygems_setup version:${version} rvm_ruby_string:${rvm_ruby_string} rvm_ruby_home:${rvm_ruby_home} rvm_ruby_binary:${rvm_ruby_binary}"

  case "${version:-missing}" in
    ignore|none)
      rvm_debug "Skipping installing rubygems."
      return 0
      ;;
  esac

  can_switch_rubygems ||
  rubygems_fatal_error "RVM can not install rubygems for maglev and older jruby, select other ruby and try again." $?

  __rvm_warn_on_rubyopt

  true ${rvm_ruby_selected_flag:=0}

  unset RUBYOPT

  (( rvm_ruby_selected_flag == 0 ))  || __rvm_select

  rubygems_select_version "$version" || return $?
  rvm_debug "rubygems_setup_rubygems version:${rvm_rubygems_version} rvm_gem_package_name:${rvm_gem_package_name} rvm_gem_url:${rvm_gem_url}"
  rvm_debug "rubygems_setup_bundler sha:${__bundler_sha} __bundler_package_name:${__bundler_package_name} __bundler_url:${__bundler_url}"

  if
    [[ "${rvm_force_flag:-0}" -eq 1 ]]
  then
    true # just let us continue with installation
  else
    \typeset __current_rubygems_version="$( rubygems_current_rubygems_version )"
    if
      __rvm_version_compare "${__current_rubygems_version}" -eq "$version"
    then
      rvm_log "Rubygems $version already available in installed ruby, skipping installation, use --force to reinstall."
      return 0
    elif
      __rvm_version_compare "${__current_rubygems_version}" -gt "$version"
    then
      rvm_log "Installed rubygems ${__current_rubygems_version} is newer than $version provided with installed ruby, skipping installation, use --force to force installation."
      return 0
    fi
  fi

  make_sure_jruby_can_work_with_rubygems ||
  rubygems_fatal_error "RVM can not install rubygems for older jruby, select other ruby and try again." $?

  # always cleanup!
  [[ -d "${rvm_src_path}/$rvm_gem_package_name" ]] ||
    __rvm_rm_rf "${rvm_src_path}/$rvm_gem_package_name"

  rvm_log "$rvm_ruby_string - #downloading $rvm_gem_package_name"
  "$rvm_scripts_path/fetch" "$rvm_gem_url" "${rvm_gem_package_name}.tgz" ||
  rubygems_fatal_error "There has been an error while trying to fetch rubygems. \nHalting the installation." $?

  if
    [[ -n "${__bundler_sha:-}" ]]
  then
    rvm_log "$rvm_ruby_string - #downloading $__bundler_package_name"
    "$rvm_scripts_path/fetch" "$__bundler_url" "${__bundler_package_name}.tgz" ||
    rubygems_fatal_error "There has been an error while trying to fetch bundler. \nHalting the installation." $?
  fi

  __rvm_log_command "rubygems.extract" "$rvm_ruby_string - #extracting $rvm_gem_package_name" \
  __rvm_package_extract "${rvm_archives_path}/$rvm_gem_package_name.tgz" "${rvm_src_path}" ||
  rubygems_fatal_error "There has been an error while trying to extract rubygems. \nHalting the installation." $?

  if
    [[ -n "${__bundler_sha:-}" ]]
  then
    __rvm_log_command "rubygems.bundler.extract" "$rvm_ruby_string - #extracting $__bundler_package_name" \
    __rvm_package_extract "${rvm_archives_path}/$__bundler_package_name.tgz" "${rvm_src_path}" "*/spec/*" ||
    rubygems_fatal_error "There has been an error while trying to extract bundler. \nHalting the installation." $?

    \rm -rf "${rvm_src_path}/$rvm_gem_package_name/bundler" &&
    ln -nfs "${rvm_src_path}/$__bundler_package_name/" "${rvm_src_path}/$rvm_gem_package_name/bundler" ||
    rubygems_fatal_error "There has been an error while linking bundler. \nHalting the installation." $?
  fi

  __rvm_log_command "rubygems.remove" "$rvm_ruby_string - #removing old rubygems" rubygems_remove "${rvm_ruby_binary}"

  __rvm_cd "${rvm_src_path}/$rvm_gem_package_name"

  \typeset -a __command
  __command=(
    GEM_HOME="$rvm_gems_path/${rvm_ruby_string}@global" GEM_PATH="" "${rvm_ruby_binary}" -d "${rvm_src_path}/$rvm_gem_package_name/setup.rb"
  )
  if [[ ${rvm_debug_flag:-0} == 1 || ${rvm_trace_flag:-0} == 1 ]]
  then __command+=( --verbose )
  fi
  if
    (( ${rvm_docs_flag:-0} == 0 ))
  then
    if __rvm_version_compare "$version" -ge 2.2
    then __command+=( --no-document )
    else __command+=( --no-ri --no-rdoc )
    fi
  fi
  __setup_lang_fallback
  __rvm_log_command "rubygems.install" \
    "$rvm_ruby_string - #installing $rvm_gem_package_name" \
    "${__command[@]}" ||
    return $?
  [[ -e "$rvm_ruby_home/bin/gem" ]] ||
  {
    \typeset program_suffix
    program_suffix="$( __rvm_ruby_config_get configure_args "${rvm_ruby_binary}" )"
    case "${program_suffix:-}" in
      (*--program-suffix=*)
        program_suffix="${program_suffix#*--program-suffix=}"
        program_suffix="${program_suffix%%[\' ]*}"
        __rvm_log_command "link.gem" "$rvm_ruby_string - #linking gem${program_suffix} -> gem" \
          ln -s "$rvm_ruby_home/bin/gem${program_suffix}" "$rvm_ruby_home/bin/gem"
        ;;
    esac
  }
  true # for osx
}

rubygems_validate_gemfile_extract()
(
  \command \mkdir -p "$2/gem" &&
  \command \tar -C "$2" -xf "$1" --touch &&
  \command \cd "$2" &&
  \command \gzip -d "metadata.gz" &&
  \command \tar -C gem -xzf "data.tar.gz" --touch &&
  \command \rm "data.tar.gz" ||
  {
    \typeset ret=$?
    rvm_error "Error extracting '$1' to '$2'."
    \command \rm -rf "${rvm_tmp_path}/rg$$"
    return $ret
  }
)

# Adapted from: https://gist.github.com/4678778
rubygems_validate_gemfile()
(
  gem_file="$1"
  downloaded_file="${gem_file##*/}"
  gem__url="${2:-https://d2chzxaqi4y7f8.cloudfront.net/gems/$downloaded_file}"
  dir_local_copy="${downloaded_file%.gem}--local"
  dir_remote_copy="${downloaded_file%.gem}-remote"

  mkdir -p "${rvm_tmp_path}/rg$$"
  cd "${rvm_tmp_path}/rg$$"

  __rvm_curl "$gem__url" -o "$downloaded_file" &&
  [[ -f "$downloaded_file" ]] ||
  {
    \typeset ret=$?
    rvm_error "Could not download '$gem__url'."
    \command \rm -rf "${rvm_tmp_path}/rg$$"
    return $ret
  }

  rubygems_validate_gemfile_extract "$gem_file"        "$dir_local_copy"  || return $?
  rubygems_validate_gemfile_extract "$downloaded_file" "$dir_remote_copy" || return $?

  # compare
  diff -ru "$dir_local_copy" "$dir_remote_copy"

  # cleanup
  \command \rm -rf "${rvm_tmp_path}/rg$$"
)

rubygems_validate_list_gemdirs()
{
  for gemdir in "$@"
  do
    __rvm_readlink_deep gemdir
    echo "${gemdir}"
  done | sort -u
}

# Adapted from: https://gist.github.com/4678189
rubygems_validate()
{
  __rvm_which openssl > /dev/null ||
    rubygems_fatal_error "'openssl' was not found, please install it."

  \typeset gemdir gemfile url gem loc rem log
  \typeset -a gemdirs

  rvm_log  "Validating RubyGems... This will take a while..."

  __rvm_read_lines gemdirs <(
    rubygems_validate_list_gemdirs "$@"
  )

  (( ${#gemdirs[@]} )) ||
  __rvm_read_lines gemdirs <(
    rubygems_validate_list_gemdirs "$rvm_gems_path"/*/cache
  )

  for gemdir in "${gemdirs[@]}"
  do
    for gem in "$gemdir"/*.gem
    do
      gemfile="${gem##*/}"
      url="https://d2chzxaqi4y7f8.cloudfront.net/gems/$gemfile"
      printf "%b" "${rvm_notify_clr}${gem}${rvm_reset_clr}"

      loc=$(openssl md5 $gem |cut -d" " -f2)
      rem=$(__rvm_curl -3 -s -D - -X HEAD -H 'Connection:close' "$url" | __rvm_grep 'ETag' | cut -d'"' -f2)

      [[ $loc == $rem ]] ||
      {
        printf "%b" " "
        log="${rvm_log_path}/$gemfile.diff"
        rubygems_validate_gemfile "$gem" "$url" > "$log"
        printf "%b" "${rvm_error_clr}mismatch, local: $loc, remote: $rem${rvm_reset_clr}, differences recorded in '$log'"
      }
      printf "%b" ", "
    done
  done

  rvm_log "\nDone verifying gems."
}
